﻿//
// *************************************************************************************
// WP-Framework
// 
// Developed by
// Lukas Kretschmar (lkretschmar.dev@bluewin.ch)
//
// Switzerland, Copyright (c) 2013 lkretschmar
// This content is released under the MIT License (http://opensource.org/licenses/MIT).
//     
// *************************************************************************************
//
//



using Microsoft.VisualStudio.TestTools.UnitTesting;
using KretschIT.WP_Fx.EasyMoq.Generator.Constraints;
using KretschIT.WP_Fx.EasyMoq.Generator.Tests.Helpers.Constraints;
using System.Linq;
using KretschIT.WP_Fx.EasyMoq.Generator.Items;
using System;
using System.Collections.Generic;
using KretschIT.WP_Fx.Testing;
using KretschIT.WP_Fx.EasyMoq.Generator.Tests.Helpers.Objects;

namespace KretschIT.WP_Fx.EasyMoq.Generator.Tests.Constraints
{
    [TestClass]
    public class GenericConstraintBuilderTest
    {
        private IGenericConstraintBuilder buider;

        [TestInitialize]
        public void Init()
        {
            this.buider = new GenericConstraintBuilder(new NamingFactory(new List<Type> 
            {
                typeof(ITestSimpleGenericObject<>),
                typeof(Helpers.OtherObjects.ITestSimpleGenericObject<>)
            }));
        }

        [TestMethod]
        public void Test_NonConstraint()
        {
            Assert.AreEqual(string.Empty, this.buider.GenericConstraint);
        }

        [TestMethod]
        public void Test_AddNonGenericType()
        {
            this.buider.AddGenericType(typeof(string));
            Assert.AreEqual(string.Empty, this.buider.GenericConstraint);
        }

        [TestMethod]
        public void Test_SimpleTypeConstraint()
        {
            var type = typeof(ISimpleTypeConstraint<>);
            var genericType = type.GetGenericArguments().Single();
            this.buider.AddGenericType(genericType);
            Assert.AreEqual(" where T : KretschIT.WP_Fx.EasyMoq.Generator.Tests.Helpers.Constraints.Class1", this.buider.GenericConstraint);
        }

        [TestMethod]
        public void Test_MultiTypeConstraint()
        {
            var type = typeof(IMultiTypeConstraint<>);
            var genericType = type.GetGenericArguments().Single();
            this.buider.AddGenericType(genericType);
            Assert.AreEqual(" where T : KretschIT.WP_Fx.EasyMoq.Generator.Tests.Helpers.Constraints.Class1, KretschIT.WP_Fx.EasyMoq.Generator.Tests.Helpers.Constraints.IInterface1", this.buider.GenericConstraint);
        }

        [TestMethod]
        public void Test_CtorConstraint()
        {
            var type = typeof(ICtorConstraint<>);
            var genericType = type.GetGenericArguments().Single();
            this.buider.AddGenericType(genericType);
            Assert.AreEqual(" where T : new()", this.buider.GenericConstraint);
        }

        [TestMethod]
        public void Test_ReferemceTypeConstraint()
        {
            var type = typeof(IReferenceTypeConstraint<>);
            var genericType = type.GetGenericArguments().Single();
            this.buider.AddGenericType(genericType);
            Assert.AreEqual(" where T : class", this.buider.GenericConstraint);
        }

        [TestMethod]
        public void Test_ValueTypeConstraint()
        {
            var type = typeof(IValueTypeConstraint<>);
            var genericType = type.GetGenericArguments().Single();
            this.buider.AddGenericType(genericType);
            Assert.AreEqual(" where T : struct", this.buider.GenericConstraint);
        }

        [TestMethod]
        public void Test_ComplexConstraint()
        {
            var type = typeof(IComplexConstraint<>);
            var genericType = type.GetGenericArguments().Single();
            this.buider.AddGenericType(genericType);
            Assert.AreEqual(" where T : class, KretschIT.WP_Fx.EasyMoq.Generator.Tests.Helpers.Constraints.IInterface1, new()", this.buider.GenericConstraint);
        }

        [TestMethod]
        public void Test_MultiGenericConstraint()
        {
            var type = typeof(IMultiGenericConstraint<Class2, int, Class1>);
            type = type.GetGenericTypeDefinition();
            foreach (var t in type.GetGenericArguments())
            {
                this.buider.AddGenericType(t);
            }
            Assert.AreEqual(" where T1 : class, new() where T2 : struct where T3 : KretschIT.WP_Fx.EasyMoq.Generator.Tests.Helpers.Constraints.Class1", this.buider.GenericConstraint);
        }

        [TestMethod]
        public void Test_GenericWithoutCondition()
        {
            var type = typeof(INonConstraint<>);
            var genericType = type.GetGenericArguments().Single();
            this.buider.AddGenericType(genericType);
            Assert.AreEqual(string.Empty, this.buider.GenericConstraint);
        }

        [TestMethod]
        public void Test_GenericWithRelationCondition()
        {
            var type = typeof(IGenericRelationConstraint<,>);
            foreach (var t in type.GetGenericArguments())
            {
                this.buider.AddGenericType(t);
            }
            Assert.AreEqual(" where T : U", this.buider.GenericConstraint);
        }

        [TestMethod]
        public void Test_GenericWithComplexCondition()
        {
            var type = typeof(IComplexGenericConstraint<,>);
            foreach (var t in type.GetGenericArguments())
            {
                this.buider.AddGenericType(t);
            }
            Assert.AreEqual(" where T : System.Collections.Generic.IEnumerable<U>", this.buider.GenericConstraint);
        }

        [TestMethod]
        public void Test_GenericWithVeryComplexCondition()
        {
            var type = typeof(IVeryComplexGenericConstraint<,,>);
            foreach (var t in type.GetGenericArguments())
            {
                this.buider.AddGenericType(t);
            }
            Assert.AreEqual(" where T : System.Collections.Generic.IDictionary<U, KretschIT.WP_Fx.EasyMoq.Generator.Tests.Helpers.Constraints.IComplexGenericConstraint<U, V>> where U : System.Collections.Generic.IEnumerable<V>", this.buider.GenericConstraint);
        }

        [TestMethod]
        public void Test_GenericWithConstraintTypesOfMultipleNamespaces()
        {
            var type = typeof(IMissUnderstandableGenericConstraint<,>);
            foreach (var t in type.GetGenericArguments())
            {
                this.buider.AddGenericType(t);
            }
            var expectedConstraint = " where T : KretschIT.WP_Fx.EasyMoq.Generator.Tests.Helpers.Objects.ITestSimpleGenericObject<T>"
                + " where U : KretschIT.WP_Fx.EasyMoq.Generator.Tests.Helpers.OtherObjects.ITestSimpleGenericObject<U>";
            Assert.AreEqual(expectedConstraint, this.buider.GenericConstraint);
        }
    }
}
